#ifndef _DRIVER_GPIO_H
#define _DRIVER_GPIO_H

#include "plf.h"
#include "driver_system.h"

/// Macro to read a platform register
#define REG_PL_RD(addr)              (*(volatile uint32_t *)(addr))

/// Macro to write a platform register
#define REG_PL_WR(addr, value)       (*(volatile uint32_t *)(addr)) = (value)


#define GPIO_PORTA_DATA         (GPIOAB_BASE + 0x00)
#define GPIO_PORTB_DATA         (GPIOAB_BASE + 0x04)
#define GPIO_PORTC_DATA         (GPIOCD_BASE + 0x08)
#define GPIO_PORTD_DATA         (GPIOCD_BASE + 0x0c)
#define GPIO_PORTE_DATA         (GPIOCD_BASE + 0x10)
#define GPIO_PORTA_DIR          (GPIOAB_BASE + 0x20)
#define GPIO_PORTB_DIR          (GPIOAB_BASE + 0x24)
#define GPIO_PORTC_DIR          (GPIOCD_BASE + 0X28)
#define GPIO_PORTD_DIR          (GPIOCD_BASE + 0x2c)
#define GPIO_PORTE_DIR          (GPIOCD_BASE + 0x30)
#define GPIO_PORT_EXTI0         (GPIOAB_BASE + 0x40)
#define GPIO_PORT_EXTI1         (GPIOCD_BASE + 0x44)


enum gpio_func_t
{
    GPIO_FUNC_GPIO = 0,
    GPIO_FUNC_EXTI = 1,
};

struct gpio_reg_exti0_t
{
    uint32_t pa_inten:8;
    uint32_t pb_inten:8;
    uint32_t pc_inten:8;
    uint32_t pd_inten:8;
};
struct gpio_reg_exti1_t
{
    uint32_t pe_inten:8;
    uint32_t res:24;
};

//gpio port write
inline void gpio_porta_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTA_DATA,value);
}
inline void gpio_portb_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTB_DATA,value);
}
inline void gpio_portc_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTC_DATA,value);
}
inline void gpio_portd_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTD_DATA,value);
}
inline void gpio_porte_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTE_DATA,value);
}
//gpio port read
inline uint8_t gpio_porta_read(void)
{
    return REG_PL_RD(GPIO_PORTA_DATA);
}
inline uint8_t gpio_portb_read(void)
{
    return REG_PL_RD(GPIO_PORTB_DATA);
}
inline uint8_t gpio_portc_read(void)
{
    return REG_PL_RD(GPIO_PORTC_DATA);
}
inline uint8_t gpio_portd_read(void)
{
    return REG_PL_RD(GPIO_PORTD_DATA);
}
inline uint8_t gpio_porte_read(void)
{
    return REG_PL_RD(GPIO_PORTE_DATA);
}

//gpio port set direction
inline void gpio_porta_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTA_DIR,dir);
}
inline void gpio_portb_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTB_DIR,dir);
}
inline void gpio_portc_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTC_DIR,dir);
}
inline void gpio_portd_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTD_DIR,dir);
}
inline void gpio_porte_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTE_DIR,dir);
}

//get gpio port direction
inline uint8_t gpio_porta_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTA_DIR);
}
inline uint8_t gpio_portb_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTB_DIR);
}
inline uint8_t gpio_portc_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTC_DIR);
}inline uint8_t gpio_portd_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTD_DIR);
}
inline uint8_t gpio_porte_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTE_DIR);
}



/*********************************************************************
 * @fn     gpio_set_func
 *
 * @brief   set  gpio interrupt and enable port
 *
 * @param   port        - @ref system_port_t.
 *          bit         - get gpio port pin @ref system_port_bit_t
 *          func        - function value. @ref gpio_func_t
 *
 * @return  None.
 */
void gpio_set_func(enum system_port_t port,enum system_port_bit_t bit,enum gpio_func_t func);
/*********************************************************************
 * @fn      gpio_set_dir_t
 *
 * @brief   set gpio input or output
 *
 * @param   type        - @ref system_port_t.
 *          bit         - @ref system_port_bit_t
 *          dir         - set gpio direction
 *
 * @return  None.
 */
extern void gpio_set_dir(enum system_port_t port,enum system_port_bit_t bit,uint8_t dir);
/*********************************************************************
 * @fn      gpio_set_pin_value_t
 *
 * @brief   set gpio pin value
 *
 * @param   type        - @ref system_port_t.
 *          bit         - @ref system_port_bit_t
 *          value       - set gpio port value
 *
 * @return  None.
 */
extern void gpio_set_pin_value(enum system_port_t port,enum system_port_bit_t bit,uint8_t value);
/*********************************************************************
 * @fn      gpio_get_pin_value_t
 *
 * @brief   get gpio pin value
 *
 * @param   type        - @ref system_port_t.
 *          bit         - @ref system_port_bit_t
 *      
 *
 * @return  value
 */
extern int8_t gpio_get_pin_value(enum system_port_t port,enum system_port_bit_t bit);

#endif
